home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Networking / OT PAPServerSample / PAPServerSample.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-28  |  50.1 KB  |  1,933 lines  |  [TEXT/CWIE]

  1. /*
  2.  
  3.     file: PAPServerSample.c
  4.     
  5.     This sample demonstrates the implementation of a PAP server using Open Transport.
  6.     
  7.     Issues:
  8.     1. PostScript Query responses are default only
  9.     To respond to the LaserWriter client, the PostScript query handler code is 
  10.     designed to return the default responses.  A real PAP spooler would have to
  11.     respond more appropriately for the printer that it is supporting.  This could mean
  12.     delaying the response back to the client until the spooler can actually
  13.     pass the query to the printer and get a real response.  The code for detecting
  14.     a PostScript query is not very robust.  The purpose of this sample was not to
  15.     demonstrate PostScript support, but to packet flow via OT.
  16.     
  17.     2. If the received data is not part of a PostScript query, the spooler sample
  18.     assumes that all of the incoming data is part of the same job.  There is no check
  19.     for the PostScript EOF indicator to distinguish different spooler jobs.  All of the 
  20.     incoming data is saved to a temporary disk file at the root of the boot hard drive.
  21.     The code does not try to preflight the amount of storage present, nor protect  
  22.     some minimum hard drive storage in case the hard drive is close to full.
  23.     
  24.     3.    This sample requires OT 1.1.2 or greater.
  25.     
  26.     4. This sample support multiple handoff endpoints.  The constant kMaxHandoffEPs
  27.     defines the maximum number of handoff endpoints that this sample supports.  I have
  28.     tested that the server supports 2 endpoint connections at the same time, but have not
  29.     gone into testing more simultaneous connections.      
  30.     
  31.     
  32.     
  33.     by:        Rich Kubota
  34.             Developer Technical Support
  35.             
  36. */
  37.  
  38. #define  HANDOFF_EP            1    // set to to to indicate use of handoff endpoint
  39.  
  40. #include <Types.h>
  41. #include <Errors.h>
  42. #include <String.h>
  43. #include <ToolUtils.h>
  44. #include "StringUtils.h"
  45. #include <AppleTalk.h>
  46. #include "OpenTransport.h"
  47. #include "OpenTptAppleTalk.h"
  48. #include "ATalkSampleUtils.h"
  49. #include "PAPServerUtilities.h"
  50. #include "PAPServerSample.h"
  51. #include "PAPPostScriptStuff.h"
  52. extern  OSStatus OTSetMemoryLimits(size_t growSize, size_t maxSize);
  53.  
  54. /********************/
  55. /*     globals            */
  56. /********************/
  57. DDPAddress        gAddr;
  58. MyEndpointRef    gEp;
  59.  
  60. #if HANDOFF_EP
  61. MyEndpointRef    gHandoffEp[kMaxHandoffEPs];
  62. #endif
  63.  
  64. OTLIFO*            gFreeQ;            // note that an OTLIFO structure must be on a 4-byte boundary
  65.                                 // instead of trying to force it to be on a 4-byte boundary in
  66.                                 // global memory, we use a pointer, then allocate memory
  67.                                 // which will force the global to be on a 4-byte boundary.
  68. UInt32            gFlags    = 0;
  69. UInt32            gBufsAvail;
  70. PacketPtr        gTempPackPtr;
  71. short            gFRefNumToClose = 0;
  72. Boolean            gDone    = false;
  73. Str255            gIdleStr;
  74. Str255            gBusyStr;
  75. Str255            gServerNBPNameStr;
  76. UInt32            gOptionCompleted; // used to flag completion of Option Management calls
  77. extern char        gEOFStr[8];
  78. extern char        gBeginPSStr[8];
  79. extern char        qBeginQueryStr[8];
  80. extern char        gEndStr[8];
  81. extern char        gQueryStr[8];
  82.  
  83. OSType            gOTVersionSelector    = 'otvr';
  84. UInt32            gOTVersion;
  85.  
  86.  
  87. /*******************************************************************************
  88. ** Prototypes
  89. ********************************************************************************/
  90.  
  91. pascal    void    EventHandler(void*, OTEventCode, OTResult, void*);
  92. static void     EnterListenAccept(MyEndpointRef *myServerEp);
  93. void            DoListenAccept(MyEndpointRef *myServerEp);
  94. Boolean         ReceiveOnePacket(MyEndpointRef *myEp, PacketPtr packetPtr);
  95. void             DoReceiveData(MyEndpointRef *myEp);
  96. OSStatus         DoDisconnect(MyEndpointRef *myEp);
  97. OSStatus         DoOrderlyDisconnect(MyEndpointRef *myEp);
  98. OSStatus         PollQueueList(void);
  99. OSErr             ProcessIncomingDataFile(MyEndpointRef *theEp, PacketPtr packetPtr);
  100. Boolean         TestDataIsPSQuery(PacketPtr packetPtr);
  101. OSStatus         ProcessPSQuery(PacketPtr packetPtr);
  102. Boolean            DoProcessPSQuery(PacketPtr packetPtr);
  103. OSErr             CheckFileToClose(void);
  104. void            DoServer(void);
  105. void            DoEvent(EventRecord *event);
  106. OSStatus         DoBind(EndpointRef ep, UInt8 socket, UInt8 type, OTQLen qlen, 
  107.                         char *nbpName, UInt32 nbpNameLen);
  108. OSStatus         ActivatePAPEndpoint(MyEndpointRef *myEp);
  109. OSStatus         InitPAPServerStuff(void);
  110. void            ClosePAPServerStuff(void);
  111. OSStatus            InitMyEndpointRef(MyEndpointRef *myEp);
  112. OSStatus         InitPAPBuffers(void);
  113. void             ReleasePAPMemory(void);
  114. extern OSStatus DoNegotiateEOMOption(EndpointRef ep, Boolean enableEOM);
  115. extern OSStatus DoSetServerStatusOption(EndpointRef ep, char *statusStr);
  116. extern OSStatus DoNegotiateSelfSendOption(EndpointRef ep, long enableSelfSend);
  117. void             DoValueBreak(long value, const char* message);
  118. OSStatus         BeginSetServerStatusOption(EndpointRef ep, UInt16 whichStr);
  119. UInt32             GetYesNoOption(void);
  120. Boolean         EndpointsAllBusy(void);
  121. #if HANDOFF_EP
  122. MyEndpointRef*    FindFreeHandoffEp(void);
  123. #endif
  124.  
  125. /*******************************************************************************
  126. ** EventHandler
  127. **  The event handler can be called at times when it is not safe to do console I/O,
  128. **  so this routine takes the event and jams it on a list to be handled when
  129. **  we know it's safe to print informative messages
  130. ********************************************************************************/
  131.  
  132. pascal void EventHandler(void* contextPtr, OTEventCode code,
  133.                                         OTResult result, void* cookie)
  134. {
  135.     
  136.     switch (code)
  137.     {
  138.         case T_LISTEN:                /* An connection request is available     */
  139.             SetListenPendFlag(((MyEndpointRef*)contextPtr)->flags);
  140.             DoListenAccept(contextPtr);
  141.             break;
  142.             
  143.         //    T_DATA:
  144.         //
  145.         //    The main rule for processing T_DATA's is to remember that once you have
  146.         //    a T_DATA, you won't get another one until you have read to a kOTNoDataErr.
  147.         //    The advanced rule is to remember that you could get another T_DATA
  148.         //    during an OTRcv() which will eventually return kOTNoDataErr, presenting
  149.         //    the application with a synchronization issue to be most careful about.
  150.         //    
  151.         //    In this application, since an OTRcv() calls are made from inside the notifier,
  152.         //    this particular synchronization issue doesn't become a problem.
  153.         //
  154.         case T_DATA:                /* Standard data is available            */
  155.                                     // check that we are in the DATAXFER state
  156.             SetHasDataFlag(((MyEndpointRef*)contextPtr)->flags);
  157.             if (TstPassconFlag(((MyEndpointRef*)contextPtr)->flags))
  158.                 DoReceiveData(contextPtr);
  159.             break;
  160.  
  161.         case T_DISCONNECT:            /* A disconnect is available            */
  162.                 // check whether there is a file open on this endpoint
  163.             DoDisconnect(contextPtr);
  164.             break;
  165.             
  166.         case T_ERROR:                /* obsolete/unused in library            */
  167.         case T_UDERR:                /* A Unit Data Error has occurred        */
  168. #if SHOW_DEBUG_FLOW
  169.             DebugStr((const unsigned char *)"\p T_ERROR called;g");
  170. #endif
  171.             break;
  172.  
  173.         case T_ORDREL:                /* An orderly release is available        */
  174.             DoOrderlyDisconnect(contextPtr);
  175.             break;
  176.  
  177.         case T_GODATA:                /* Flow control lifted on standard data    */
  178.                                     // for this sample, I do not expect this event to occur.
  179. #if SHOW_DEBUG_FLOW
  180.             DebugStr((const unsigned char *)"\p T_GODATA called;g");
  181. #endif
  182.             break;
  183.  
  184.         case T_GOEXDATA:            /* Flow control lifted on expedited data*/
  185.                                     // for this sample, I do not expect this event to occur.
  186. #if SHOW_DEBUG_FLOW
  187.             DebugStr((const unsigned char *)"\p T_GOEXDATA called;g");
  188. #endif
  189.             break;
  190.  
  191.         case T_PASSCON:                /* State is now case T_DATAXFER            */
  192.                     // set the passcon flag
  193.                 // set flag to indicate that the endpoint is busy
  194.             SetEPBusyFlag(((MyEndpointRef*)contextPtr)->flags);
  195.                 // set flag to teel system to set server status flag appropriately
  196.                 // for multiple handoff endpoint servers, this would need to be
  197.                 // handled differently.
  198.             SetCheckOptFlag(gFlags);
  199.  
  200.             SetPassconFlag(((MyEndpointRef*)contextPtr)->flags);
  201.  
  202.                         // Set the timer for this connection
  203.             OTGetTimeStamp(&((MyEndpointRef*)contextPtr)->timerDog);
  204.  
  205.                     // check to see if there is any data to process
  206.             DoReceiveData(contextPtr);
  207.             break;
  208.             
  209.         case T_RESET:                /* Protocol has been reset                */
  210. #if SHOW_DEBUG_FLOW
  211.             DebugStr("\p T_RESET called;g");
  212. #endif
  213.             break;
  214.  
  215.         case T_ACCEPTCOMPLETE:        /* Accept call is complete                */
  216. #if SHOW_DEBUG_FLOW
  217.             DebugStr("\p T_ACCEPTCOMPLETE called;g");
  218. #endif
  219.             ClrAcceptPendFlag(((MyEndpointRef*)contextPtr)->flags);
  220.             break;
  221.  
  222.         case T_DISCONNECTCOMPLETE:    /* Disconnect call is complete            */
  223.             break;
  224.         
  225.         case T_UNBINDCOMPLETE:
  226. #if SHOW_DEBUG_FLOW
  227.             DebugStr("\p T_UNBINDCOMPLETE called;g");
  228. #endif
  229.             SetCheckOptFlag(gFlags);
  230.             ClrEPBusyFlag(((MyEndpointRef*)contextPtr)->flags);
  231.  
  232.             SetStatusIdleFlag(gFlags);
  233.  
  234.             ClrEPBoundFlag(((MyEndpointRef*)contextPtr)->flags);    // is the server endpoint bound
  235.             break;
  236.             
  237.         //
  238.         //    kStreamIoctlEvent:
  239.         //
  240.         //    This event is returned when an I_FLUSH ioctl has completed.
  241.         //    The flush was done in an attempt to get back all T_MEMORYRELEASED events
  242.         //    for outstanding OTSnd() calls with Ack Sends.   Errors are ignored at this point since it is
  243.         //    possible that the connection will already be gone, etc.
  244.         //
  245.         case kStreamIoctlEvent:
  246.             return;
  247.             break;
  248.         
  249.         case T_OPTMGMTCOMPLETE:
  250.             gOptionCompleted = 1;
  251.             break;
  252.  
  253.         default:
  254.             break;
  255.     }
  256. }
  257.  
  258. //
  259. //    EnterListenAccept
  260. //
  261. //    This is a front end to DoListenAccept() which is used whenever 
  262. //    it is not being called from inside the listener endpoint's notifier.
  263. //    We do this for syncrhonization.   If we were processing an OTListen()
  264. //    or an OTAccept() and we were interrupted at the listener endpoint's
  265. //    notifier with a T_LISTEN, etc, it would be inconvenient and would require
  266. //    some more sophisticated synchronization code to deal with the problem.
  267. //    The easy way to avoid this is to do an OTEnterNotifier() on the listener's
  268. //    endpoint.   
  269. //
  270. //    Important note - doing OTEnterNotifier on one endpoint only prevents that
  271. //    endpoint's notifier for interrupting us.   Since the same notifier code
  272. //    is used for lots of endpoints here, remember that the one endpoint's 
  273. //    notifier can interrupt another.   Doing an OTEnterNotifier() on the
  274. //    listener endpoint prevents the listener from interrupting us, but it
  275. //    does not prevent the Notifier() routine from interrupting us via 
  276. //    another endpoint which also uses the same routine.
  277. //
  278. //    Important note #2 - Don't ever do an OTEnterNotifier on an acceptor endpoint
  279. //    before doing the OTAccept().   This confuses OT and creates problems.
  280. //
  281. static void EnterListenAccept(MyEndpointRef *myServerEp)
  282. {
  283.     Boolean    doLeave;
  284.     
  285.     doLeave = OTEnterNotifier(myServerEp->ep);
  286.     DoListenAccept(myServerEp);
  287.     if (doLeave)
  288.         OTLeaveNotifier(myServerEp->ep);
  289. }
  290.  
  291. /*
  292.     DoListenAccept is designed to handle an incoming connect request.  This module demonstrates a
  293.     very complex task that all X/OPEN style acceptors must implement.  The problem stems from
  294.     fact that an endpoint may be hit by a number of simultaneous connect requests.  In addition
  295.     if there is a connection already established and the endpoint handles multiple
  296.     handoff endpoints, then there could also be an incoming disconnect request to process before
  297.     one can issue either an Accept or Disconnect response, all pending Connect requests must
  298.     be consumed from the streamhead first.  This places a burden on the accept routine to have
  299.     a place to temporarily stash all of the addresses to which discon messages will have to be
  300.     sent.
  301.     
  302.     Refer to Tech Note 1059 for the 8 steps to handling an incoming connection request.
  303.     
  304.     Note that once all of the connect request have been consumed and we are in the process of
  305.     sending discon responses, it could be that there will again be an kOTLookErr, which
  306.     indicates that another incoming connect request heeds to be consumed before
  307.     resuming with the discon responses.
  308.     
  309.     In this sample we consume the first listen request.  We then check whether we can accept
  310.     the incoming request, If so, then call OTAccept.  If OTAccept fails with a lookErr, then 
  311.     there is another connect request to be consumed.
  312.     
  313.     processed.
  314.     
  315. */
  316. void DoListenAccept(MyEndpointRef *myServerEp)
  317. {
  318.     MyEndpointRef    *myAcceptEp;
  319.     OSStatus    err;
  320.     TDiscon        discon;
  321.     OTResult    result;
  322.     TCall        call;
  323.     short        i;
  324.     Boolean        done = false;
  325.     
  326.         // check we have already entered DoListenAccept from the main event loop and are 
  327.         // trying to do so again from the secondary interrupt
  328.     if (OTAtomicSetBit(&myServerEp->semaphore, kInListenLoop))
  329.         return;    // if the bit was previous set, then we already have entered, but not exitted
  330.                 // this proc from the main event loop
  331.  
  332.     if (TstAcceptPendFlag(myServerEp->flags))
  333.     {
  334.             // we're waiting for an Accept call to complete, so don't accept a new
  335.             // connection request as we will get an out of state error
  336.             // set the ListenPendFlag so we will check the server endpoint later
  337.         
  338.         SetListenPendFlag(myServerEp->flags);
  339.         done = true;
  340.     }
  341.     else
  342.         ClrListenPendFlag(myServerEp->flags);
  343.     
  344.     if (done == false)
  345.     {
  346.             // clear out the TCall structure
  347.         memset(&call, 0, sizeof(TCall));
  348.         
  349.             // set up the TCall structure
  350.         call.addr.maxlen = sizeof(struct DDPAddress);
  351.         call.addr.len = sizeof(struct DDPAddress);
  352.         call.addr.buf = (unsigned char *) &gAddr;
  353.                 
  354.         if (OTIsSynchronous(myServerEp->ep) == true)
  355.             OTSetAsynchronous(myServerEp->ep);
  356.             
  357.             // step 1 for handling an incoming connection request
  358.         err = OTListen(myServerEp->ep, &call);
  359.         
  360.         if (err == kOTNoDataErr)
  361.         {
  362. #if SHOW_DEBUG_FLOW
  363.             DebugStr("\p kOTNoDataErr returned by OTListen");
  364. #endif
  365.                 // don't need to do anything
  366.         }
  367.         else if (err == kOTLookErr)
  368.         {
  369.                 // step 2 for handling incoming connection requests
  370.                 // handle disconnect indications for a pending connection request
  371.                 // the only look indication allowed on an OTListen call is
  372.                 // T_DISCONNECT
  373.             result = OTLook(myServerEp->ep);
  374.             if (result == T_DISCONNECT)
  375.             {
  376.                     // this is what we were expecting
  377.                     // the disconnect is for an outstanding listen request
  378.                 err = OTRcvDisconnect(myServerEp->ep, &discon);
  379.                     
  380.             }
  381.             else
  382.             {
  383. #if SHOW_DEBUG_FLOW
  384.                 DebugStr((const unsigned char *)"\p unknown event returned by OTLook");
  385. #endif
  386.             }
  387.             done = true;
  388.              
  389.         }
  390.         else if (err != kOTNoError) // there was an unknown error in doing the listen
  391.         {
  392.             DoValueBreak((long)err, "error occured on OTListen #");
  393.             done = true;
  394.  
  395.         }
  396.     }
  397.     
  398.     if (done == false)
  399.     {
  400. #if HANDOFF_EP
  401.         myAcceptEp = FindFreeHandoffEp();
  402. #else
  403.         if (TstEPBusyFlag(myServerEp.flags) == false)
  404.             myAcceptEp = myServerEp;
  405.         else
  406.             myAcceptEp = nil;
  407. #endif         
  408.     }
  409.     
  410.     if (myAcceptEp == nil)
  411.     {
  412.             // if there are no available handoff endpoints, then send the disconnect
  413.         OTSndDisconnect(myServerEp->ep, &call);
  414.         done = true;
  415.     }
  416.     
  417.     if (done == false)
  418.     {
  419.     
  420.             // set a flag to indicate that an accept call is pending
  421.             // if we try to accept another connection before this
  422.             // accept call is completed, an out of state error results 
  423.             // need to do this before we make the OTAccept call
  424.         SetAcceptPendFlag(myServerEp->flags);
  425.         
  426.             // make the accept call and handoff the connection
  427.         err = OTAccept(myServerEp->ep, myAcceptEp->ep, &call);
  428.  
  429. #if SHOW_DEBUG_FLOW
  430.             DoValueBreak((long)err, "OTAccept returned #");
  431. #endif
  432.  
  433.         if (err == kOTNoError)
  434.         {
  435.             SetEPBusyFlag(myAcceptEp->flags);
  436.  
  437.                 // set flag to have server check the serverstatus
  438.             TstCheckOptFlag(gFlags);
  439.                         
  440.         }
  441.         else if (err == kOTLookErr)
  442.         {
  443.                 // an OTLookErr for an OTAccept call means that there is 
  444.                 // either an T_LISTEN or T_DISCONNECT event
  445.                 
  446.                 // check what event is on the pipe
  447.             result = OTLook(myServerEp->ep);
  448.             if (result == T_DISCONNECT)
  449.             {
  450.                 err = OTRcvDisconnect(myServerEp->ep, &discon);
  451.                     
  452.             }
  453.         
  454.         }
  455.         else
  456.         {
  457. #if HANDOFF_EP
  458.             DoValueBreak((long)err, "error occured on OTAccept for handoff #");
  459. #else
  460.             DoValueBreak((long)err, "error occured on OTAccept #");
  461. #endif
  462.  
  463.         }
  464.     }
  465.     
  466.         
  467.     OTAtomicClearBit(&myServerEp->semaphore, kInListenLoop);    // clear the bit that indicates we're in this loop
  468.     
  469. }
  470.  
  471. /*******************************************************************************
  472. ** ReceiveOnePacket - makes the call to receive just one packet
  473. ** If there is data, then the data is placed into the packetPtr
  474. ** and the incoming byte count is incremented
  475. ** if the kOTNoDataErr occurs, then the HasDataFlag is cleared.
  476. ** 
  477. **   
  478. ********************************************************************************/
  479. Boolean ReceiveOnePacket(MyEndpointRef *myEp, PacketPtr packetPtr)
  480. {
  481.     UInt32        localFlag = 0;
  482.     OTResult     result, res;
  483.     Boolean        done = false;
  484.                     
  485.     result = OTRcv(myEp->ep, &packetPtr->data, kPAPDataSize, &packetPtr->flags);
  486.     if (result < 0)
  487.     {
  488.             // requeue the buffer to the freeq
  489.         OTLIFOEnqueue(gFreeQ, &(packetPtr->fLink));
  490.         done = true;
  491.         
  492.         if (result == kOTLookErr)
  493.         {
  494.             res = OTLook(myEp->ep);
  495.                 // for an OTRcv call, there are only 2 OTLook responses
  496.             if (res == T_DISCONNECT)
  497.             {
  498.                 res = DoDisconnect(myEp->ep);
  499.                     // if we get a disconnect event, then there will be no more
  500.                     // data in the pipe.
  501. #if SHOW_DEBUG_FLOW
  502.                 DebugStr("\p processing disconnect in OTRcv;g");
  503. #endif
  504.                 ClrOrdDisconFlag(myEp->flags);
  505.                 ClrInPSQueryFlag(myEp->flags);
  506.             }
  507.             else if (res == T_ORDREL)
  508.             {
  509. #if SHOW_DEBUG_FLOW
  510.                 DebugStr("\p processing orderly disconnect in OTRcv;g");
  511. #endif
  512.                 res = DoOrderlyDisconnect(myEp->ep);
  513.                 localFlag = 1;
  514.             }
  515.             
  516.         }
  517.         else if (result == kOTOutStateErr)
  518.         {
  519.                 // client could have issued a disconnect call while this call was about to
  520.                 // to be processed
  521.             ClrHasDataFlag(myEp->flags);
  522.         }
  523.         
  524.         else if (result == kOTNoDataErr)
  525.         {
  526.                 // no more data so clr the flag
  527.             ClrHasDataFlag(myEp->flags);
  528.         }
  529.         else 
  530.         {
  531. #if SHOW_DEBUG_FLOW
  532.             DebugStr("\pUnknown error occurred in OTRcv");
  533. #endif
  534.         }
  535.     }
  536.     else if (result == 0)
  537.     {
  538. #if SHOW_DEBUG_FLOW
  539.         DebugStr("\p OTRcv got nothing ;g");
  540. #endif
  541.         
  542.         if (TstInPSQueryFlag(myEp->flags))    // check if the endpoint is already processing a postscript
  543.         {
  544. #if SHOW_DEBUG_FLOW
  545.             DebugStr("\p 0 byte packet while processing ps query ;g");
  546. #endif
  547. #if SHOW_DEBUG_FLOW
  548.             if (packetPtr->flags & T_MORE == 0)
  549.                 DebugStr("\p T_MORE was not set;g");
  550.             else
  551.                 DebugStr("\p T_MORE was set;g");
  552. #endif
  553.                 // send an empty response with EOF flasg set since it appears that this is what the Laserwriter 
  554.                 // client wants to see.
  555.             packetPtr->theEp = myEp;
  556.             SendEmptyPacket(packetPtr);
  557.                 // clear bit that indicates we are processing a postscript query
  558.             ClrInPSQueryFlag(myEp->flags);
  559. #if SHOW_DEBUG_FLOW
  560.     
  561.             DebugStr("\p Have finished ps query;g");
  562. #endif
  563.         }
  564.         
  565.             // requeue the buffer to the freeq since no data was returned
  566.         OTLIFOEnqueue(gFreeQ, &(packetPtr->fLink));
  567.     }
  568.     else
  569.     {
  570.  
  571.         if (TstdumpPktsFlag(gFlags))
  572.         {
  573.             OTLIFOEnqueue(gFreeQ, &(packetPtr->fLink));
  574.         }
  575.         else
  576.         {
  577.             
  578.                         // save the endpoint ref associated with this data
  579.             packetPtr->theEp = myEp;
  580.             
  581.                         // save the number of bytes read
  582.             packetPtr->numBytes = result;
  583.             
  584.                         // intialize the lastPos field
  585.             packetPtr->lastPos = 0;
  586.             
  587.                         // get the timestamp for this packet
  588.             OTGetTimeStamp(&packetPtr->timeStamp);
  589.             
  590.                         // Set the timer for this connection
  591.             OTGetTimeStamp(&myEp->timerDog);
  592.             
  593.             if (!DoProcessPSQuery(packetPtr))
  594.             {
  595.                     // packet is not a postscript query so queue to the endpoint usedQ
  596.                     // queue the buffer to the usedQ associated with the endpoint
  597.                 OTLIFOEnqueue(myEp->usedQ, &(packetPtr->fLink));
  598.                 
  599.             }
  600.         
  601.         }
  602.  
  603.     }
  604.     
  605.     return done;
  606.         
  607. }
  608.  
  609.  
  610. /*******************************************************************************
  611. ** DoReceiveData
  612. **   
  613. ********************************************************************************/
  614. void DoReceiveData(MyEndpointRef *myEp)
  615. {
  616.     PacketPtr    packetPtr;
  617.     OTFlags        flags = 0;
  618.     UInt32        localFlag = 0;
  619.     OTResult     result, res;
  620.     Boolean        done;
  621.     
  622.         // check we have already entered DoReceiveData from the main event loop
  623.         // or from the event handler and are 
  624.         // trying to do so again a second time
  625.     if (OTAtomicSetBit(&myEp->semaphore, kInRcvDataFlag))
  626.         return;    // if the bit was previous set, then we already have entered, but not exitted
  627.                 // this proc from the main event loop
  628.  
  629.     done = gDone;
  630.     while (done == false)
  631.     {
  632.         if (gFreeQ->fHead != nil)
  633.         {
  634.             packetPtr = (PacketPtr)OTLIFODequeue(gFreeQ);
  635.             done = ReceiveOnePacket(myEp, packetPtr);
  636.         }
  637.         else
  638.         {
  639.             
  640.             done = true;
  641.         }
  642.             
  643.         
  644.     }
  645.  
  646.     OTAtomicClearBit(&myEp->semaphore, kInRcvDataFlag);    
  647.                 // clear the bit that indicates we're in this loop
  648.                         
  649. }
  650.  
  651.  
  652. OSStatus DoDisconnect(MyEndpointRef *myEp)
  653. {
  654.     OSStatus        err;
  655.     
  656.  
  657.     err = OTRcvDisconnect(myEp->ep, NULL);
  658.     if (err != kOTNoError)
  659.     {
  660. #if SHOW_DEBUG_FLOW
  661.         DoValueBreak((long)err, "error occured on OTRcvDisconnect #");
  662. #endif
  663.     }
  664.     else
  665.     {
  666.         if (TstAcceptPendFlag(myEp->flags))
  667.             ClrAcceptPendFlag(myEp->flags);
  668.     }
  669.  
  670.     return err;
  671. }
  672.  
  673. OSStatus DoOrderlyDisconnect(MyEndpointRef *myEp)
  674. {
  675.     OSStatus        err;
  676.     
  677.     err = OTRcvOrderlyDisconnect(myEp->ep);
  678.     if (err < kOTNoError)
  679.     {
  680. #if SHOW_DEBUG_FLOW
  681.         DoValueBreak((long)err, "error occured on OTRcvOrderlyDisconnect #");
  682. #endif
  683.     }
  684.     else if (err > 0)
  685.     {            
  686. #if SHOW_DEBUG_FLOW
  687.         DebugStr("\p OTRcvOrderlyDisconnect returned positive result;g");
  688. #endif
  689.         SetOrdDisconFlag(myEp->flags);
  690.     }
  691.     else
  692.     {
  693.         SetOrdDisconFlag(myEp->flags);
  694.     }
  695.     
  696.     return err;
  697. }
  698.  
  699. /*******************************************************************************
  700. ** PollEventList
  701. **  This routine checks the used queue to see whether the handler has processed
  702.     incoming PAP data from the client.
  703. **    If the used queue is not empty, there are two different options to deal with.
  704.     First we check whether we are in the middle of processing a postscript data
  705.     file.  If so, we continue to read the data into a file which we have created.
  706.     If not currently processing postscript data, we then check to see if the incoming
  707.     packet is part of a postscript query in progress or is the beginning of a 
  708.     postscript query.  If so, we continue to read the query and respond as appropriate.
  709.     If not a query, then this must be the first packet of postscript data being sent.
  710. ********************************************************************************/
  711.  
  712. OSStatus PollQueueList(void)
  713. {
  714.     PacketPtr    packetPtr, nextPacketPtr;
  715.     MyEndpointRef *theEp;
  716.     OSStatus    err = kOTNoError;
  717.     short        i = 0;
  718.     Boolean        done = false;
  719.  
  720. #if SHOW_DEBUG_FLOW
  721.     short        num = 0;
  722.     Boolean        inLoop = false;
  723. #endif
  724.     
  725. #if HANDOFF_EP
  726.     for (i = 0; (i < kMaxHandoffEPs) && (err == kOTNoError); i++)
  727.     {
  728.         theEp = &gHandoffEp[i];
  729. #else
  730.         theEp = &gEp;
  731. #endif
  732.  
  733.         packetPtr = (PacketPtr)OTLIFOStealList(theEp->usedQ);
  734.         while (packetPtr != nil)
  735.         {
  736.  
  737. #if SHOW_DEBUG_FLOW
  738.             inLoop = true;
  739. #endif
  740.             packetPtr = (PacketPtr)OTReverseList((OTLink*)packetPtr);
  741.             do
  742.             {
  743. #if SHOW_DEBUG_FLOW
  744.                 num++;
  745. #endif
  746.                 nextPacketPtr = (PacketPtr)packetPtr->fLink.fNext;
  747.                 
  748.                 err = ProcessIncomingDataFile(theEp, packetPtr);
  749.         
  750.                     // queue the packetPtr back to the freeQ
  751.                 OTLIFOEnqueue(gFreeQ, &(packetPtr->fLink));
  752.  
  753.                 packetPtr = nextPacketPtr;
  754.                 
  755.             } while((packetPtr != nil) && (err == kOTNoError));
  756.             
  757.             packetPtr = (PacketPtr)OTLIFOStealList(theEp->usedQ);
  758.         }
  759.  
  760. #if HANDOFF_EP
  761.     }
  762. #endif
  763.                 
  764. #if SHOW_DEBUG_FLOW
  765.     if (inLoop)
  766.     {
  767. //        fprintf(stdout, "numbers packets processed by PollQueueList %d\n", num);
  768.     }
  769. #endif
  770.     
  771.     return err;
  772. }
  773.  
  774. OSErr ProcessIncomingDataFile(MyEndpointRef *theEp, PacketPtr packetPtr)
  775. {
  776.     OSStatus        err = noErr;
  777.     short            fRefNum;
  778.     
  779.     
  780.         // For each incoming packet, we need to check whether it
  781.         // contains postscript query requests, or if we have not yet
  782.         // received the EOF
  783.  
  784.     if (!TstdumpPktsFlag(gFlags))    // check if we are dumping the packets
  785.     {
  786.         if (!TstTempFileFlag(theEp->flags)) // is there a temp file opened for this endpoint
  787.         {
  788.                 // no, so create one
  789.             err = OpenTempFile(&fRefNum);
  790.             if (err == noErr)
  791.             {
  792.                 fprintf(stdout, "processing incoming file\n");
  793.                 theEp->fRefNum = fRefNum;        // save the refnum of the temp file;
  794.                 SetTempFileFlag(theEp->flags);    // indicate that there is a temp file associated
  795.                                                 // with this endpoint.
  796.                     // set the time Data In timestamp field
  797.                 BlockMove((Ptr)&packetPtr->timeStamp, (Ptr)&theEp->timeDataIn, sizeof(OTTimeStamp));
  798.                     // reset the numBytesIn field to zero
  799.                 theEp->numBytesIn = 0;
  800.             }
  801.             
  802.         }
  803.     }
  804.  
  805.  
  806.     if (err == noErr)
  807.     {
  808.         
  809.         if (!TstdumpPktsFlag(gFlags))    // check if we are dumping the packets
  810.         {
  811.                 // the temp file has been created or already exists, so read the data and write it
  812.                 // to the temp file
  813.             err = WriteDataToTempFile(theEp->fRefNum, packetPtr->data, packetPtr->numBytes);
  814.         }
  815.         
  816.         if (err != noErr)
  817.         {
  818. #if SHOW_DEBUG_FLOW
  819.             DoValueBreak((long)err, "error occured writing data to tempfile #");
  820. #endif
  821.         }
  822.         else
  823.         {
  824.                 // set the time data end timestamp field
  825.             BlockMove((Ptr)&packetPtr->timeStamp, (Ptr)&theEp->timeDataEnd, sizeof(OTTimeStamp));
  826.                 // add the number of bytes in the packet to the numBytesIn field
  827.             theEp->numBytesIn += packetPtr->numBytes;
  828.  
  829.                 // check if we've read the last packet for the file
  830.             if ((packetPtr->flags & T_MORE) == 0)
  831.             {
  832.                 if (!TstdumpPktsFlag(gFlags))
  833.                 {
  834.                     fprintf(stdout, "T_MORE flag not set \n");
  835.                     
  836.                     // the proper way to detect the end of a file is to look for
  837.                     // the EOF flag at the end of the file.
  838.                     // It also appears that looking for the T_MORE flag to be clear
  839.                     // is not a reliable way to detect the end of a file.
  840.                     // When a status request is sent by the client that is sending
  841.                     // data, the T_MORE flag appears to be cleared for the incoming 
  842.                     // packet.
  843.                 }
  844.                 
  845.             }
  846.                 
  847.         }
  848.     }
  849.     
  850.     return err;
  851. }
  852.  
  853.  
  854.  
  855.  
  856. OSErr CheckFileToClose(void)
  857. {
  858.     OSErr    err = noErr;
  859.     
  860.     if (gFRefNumToClose != 0)
  861.     {
  862.         fprintf(stdout, "\n\nAm about to close file with fRefNum %ld.\n", gFRefNumToClose);
  863.         
  864.         err = CloseTempFile(gFRefNumToClose);
  865.         if (err != noErr)
  866.             fprintf(stdout, "\n\nError occurred closing file - error %ld.\n", err);        
  867.         
  868.             // reset the tempfile to close so that we don't close this file again
  869.         gFRefNumToClose = 0;
  870.     }
  871.     
  872.     return err;
  873. }
  874.  
  875.  
  876. /*******************************************************************************
  877. ** DoServer
  878. ********************************************************************************/
  879.  
  880. void DoServer(void)
  881. {
  882.     EventRecord        theEvent;
  883.     OTTimeStamp        eTime;
  884.     OTResult        state;
  885.     UInt32            eTimeMSec, sec, msec, rate;
  886.     MyEndpointRef    *theEp;
  887.     OSStatus         err1, err = kOTNoError;
  888. #if HANDOFF_EP
  889.     short            i = 0;
  890. #endif
  891.     
  892.     while (gDone == false)
  893.     {
  894.         if (!WaitNextEvent(everyEvent, &theEvent, 15, nil))
  895.             theEvent.what = nullEvent;
  896.             
  897.         DoEvent(&theEvent);
  898.         
  899.         if (TstListenPendFlag(gEp.flags))        // are there incoming connect requests to process
  900.         {
  901.             fprintf(stdout, "\n processing EnterListenAccept from even tloop");
  902.             EnterListenAccept(&gEp);
  903.         }
  904.             
  905.         err = PollQueueList();
  906.         if (err != kOTNoError)        // we're outta here if an error occurred.
  907.             gDone = true;
  908.  
  909. #if HANDOFF_EP
  910.         theEp = &gHandoffEp[i];
  911.         i++;
  912.         if (i >= kMaxHandoffEPs)
  913.             i = 0;
  914. #else
  915.         theEp = &gEp;
  916. #endif
  917.             // get the current endpoint state
  918.         state = OTGetEndpointState(theEp->ep);
  919.         
  920.         switch (state)
  921.         {
  922.             case T_DATAXFER:
  923.                     
  924.                     // check if we haven't completed reading data from OT.  
  925.                 DoReceiveData(theEp);
  926.                 break;
  927.                 
  928.             case T_INREL:    // we've processed an incoming Orderly Release request
  929.                             // but have not issued our own orderly disconnect
  930.                 
  931.  
  932.                     // note that since we have already processed an incoming orderly disconnect
  933.                     // we are in the INREL state.  After making the OTSndOrderlyDisconnect
  934.                     // call, there will not be a T_DISCONNECTCOMPLETE call, since we complete
  935.                     // the orderly release with the above call.  We go ahead and reset our flags
  936.                     // and issue the OTUnbind call if we are using a handoff endpoint.
  937.                     // if we did get the orderly release indication, then make sure we have
  938.                     // drained the receive queue - PollQueueList does this
  939.  
  940.                 do
  941.                 {
  942.                     fprintf(stdout, "processing some last data\n");
  943.                     PollQueueList();
  944.                 
  945.                         // check if we haven't completed reading data from OT. 
  946.                     DoReceiveData(theEp);
  947.                     
  948.                 }while( (TstHasDataFlag(theEp->flags)) || (theEp->usedQ->fHead != nil));
  949.  
  950.                     // clear the flag and send a corresponding disconnect
  951.                 err = OTSndOrderlyDisconnect(theEp->ep);
  952.                 if (err)
  953.                 {
  954.                     // the only error that makes sense here is the kOTLookErr
  955.                     //  which the only event is the T_DISCONNECT event.  This should not happen,
  956.                     // however, if there are multiple handoffs, this may be an issue.  Given the way
  957.                     // incoming requests are handled, I don't expect that there would be an 
  958.                     // unresponded listen request here that would warrant a possible T_DISCONNECT
  959.                     // however some implementation will need to consider this possibility.
  960. #if SHOW_DEBUG_FLOW
  961.                     DoValueBreak((long)err, "error occured on OTSndOrderlyDisconnect #");
  962.                     
  963.                     DebugStr("\p quitting program");
  964. #endif
  965.                     gDone = true;
  966.  
  967.                 }
  968.                                     
  969.                 ClrOrdDisconFlag(theEp->flags);
  970.     
  971.                 if (TstTempFileFlag(theEp->flags))
  972.                 {    
  973.                                                         // is there an open spool file associated with this endpoint
  974.                     gFRefNumToClose = theEp->fRefNum;    // set the global to have this file closed
  975.                                                     // note that this method of signalling for a file to
  976.                                                     // get closed is a quick and dirty method and assumes th
  977.                                                     // that only one file at a time is being processed here.
  978.                     CheckFileToClose();
  979.                 }
  980.                 
  981.                 ClrTempFileFlag(theEp->flags);
  982.                 ClrPassconFlag(theEp->flags);
  983.  
  984. #if HANDOFF_EP
  985.                     // in order to re-use a handoff endpoint, it must be unbound.  Unbinding the 
  986.                     // endpoint clears the connection information that allows to to know which
  987.                     // endpoint, incoming PAP data is routed to.
  988.                 if (theEp->ep != gEp.ep)
  989.                 {
  990.                     OTUnbind(theEp->ep);
  991.     
  992.                 }
  993. #else
  994.                     // indicate that we are no longer busy
  995.                 ClrEPBusyFlag(theEp->flags);
  996.                     // set flag so that we will check the status
  997.                 SetCheckOptFlag(gFlags);
  998.                 SetStatusIdleFlag(gFlags);
  999.                     
  1000. #endif
  1001.                     
  1002.                 
  1003.                     // calculate the elapsed time
  1004.                 OTSubtractTimeStamps(&eTime, &theEp->timeDataIn, &theEp->timeDataEnd);
  1005.                     // convert to millisecs
  1006.                 eTimeMSec = OTTimeStampInMilliseconds(&eTime);
  1007.                 sec = eTimeMSec / (UInt32)1000;
  1008.                 msec = eTimeMSec %(UInt32)1000;
  1009.                 fprintf(stdout, "Time to transfer file was %ld.%ld seconds.\n", sec, msec);
  1010.                 fprintf(stdout, "Bytes transferred was - %ld.\n", theEp->numBytesIn);
  1011.  
  1012.                 if (sec != 0)
  1013.                 {
  1014.                     rate = (theEp->numBytesIn / sec) / 1024;
  1015.                     fprintf(stdout, "Transfer rate - %ld KBytes/Sec. \n", rate);
  1016.                 }
  1017.                 else if (msec != 0)
  1018.                 {
  1019.                     rate = (theEp->numBytesIn *1000 / msec) / 1024;
  1020.                     fprintf(stdout, "Transfer rate - %ld KBytes/Sec. \n", rate);
  1021.                 }
  1022.                 break;
  1023.                 
  1024.             case T_IDLE:    // we're either really idle, or the we've processed a disconnect event
  1025.                             // if we processed a disconnect event then the busy flag for the ep would still be set
  1026.                 if (TstEPBusyFlag(theEp->flags))    // we're we previously connected
  1027.                 {
  1028.                     ClrPassconFlag(theEp->flags);    // clear the flag so that we can accept a new connection
  1029.                     ClrOrdDisconFlag(theEp->flags);
  1030.                     
  1031.                     ClrTempFileFlag(theEp->flags);
  1032.                     ClrPassconFlag(theEp->flags);
  1033.  
  1034.                     if (TstTempFileFlag(theEp->flags))    
  1035.                                                             // is there an open spool file associated with this endpoint
  1036.                         gFRefNumToClose = theEp->fRefNum;    // set the global to have this file closed
  1037.                                                         // note that this method of signalling for a file to
  1038.                                                         // get closed is a quick and dirty method and assumes th
  1039.                                                         // that only one file at a time is being processed here.
  1040.  
  1041. #if HANDOFF_EP
  1042.                         // in order to re-use a handoff endpoint, it must be unbound.  Unbinding the 
  1043.                         // endpoint clears the connection information that allows to to know which
  1044.                         // endpoint, incoming PAP data is routed to.
  1045.                     if (theEp->ep != gEp.ep)
  1046.                     {
  1047.                         OTUnbind(theEp->ep);
  1048.         
  1049.                     }
  1050. #else
  1051.                         // set flag so that we will check the status
  1052.                     SetCheckOptFlag(gFlags);
  1053.                         // indicate that we are no longer busy
  1054.                     ClrEPBusyFlag(theEp->flags);
  1055.                     SetStatusIdleFlag(gFlags);
  1056.  
  1057. #endif
  1058.                 }
  1059.                 break;
  1060.                 
  1061.         }
  1062.         
  1063.         
  1064.         err1 = CheckFileToClose();
  1065.         if (err1 != noErr)
  1066.             fprintf(stdout, "\n\nCheckFileToClose error - %ld.\n", err1);
  1067.     
  1068.         if (TstCheckOptFlag(gFlags))
  1069.         {
  1070.             
  1071.             if (EndpointsAllBusy())
  1072.             {
  1073.                 if (TstStatusBusyFlag(gFlags) == false)
  1074.                 {
  1075.                     BeginSetServerStatusOption(gEp.ep, kSetBusyStr);
  1076.                     SetStatusBusyFlag(gFlags);
  1077.                 }
  1078.             }
  1079.             else
  1080.             {
  1081.                 if (TstStatusBusyFlag(gFlags) == true)
  1082.                 {
  1083.                     BeginSetServerStatusOption(gEp.ep, kSetIdleStr);
  1084.                     ClrStatusBusyFlag(gFlags);
  1085.                 }
  1086.             }
  1087.             ClrCheckOptFlag(gFlags);
  1088.         }
  1089.                     
  1090.  
  1091.     }
  1092.  
  1093. }
  1094.  
  1095. /* Do the right thing for an event.  Determine what kind of event it is, and
  1096. ** call the appropriate routines. */
  1097.  
  1098. void    DoEvent(EventRecord *event)
  1099. {
  1100.     Point    pt;
  1101.     char    key;
  1102.  
  1103.     switch(event->what) 
  1104.     {
  1105.  
  1106.         case nullEvent:
  1107.         case mouseDown:
  1108.         case activateEvt:
  1109.         case updateEvt:
  1110.         case kHighLevelEvent:
  1111.             break;
  1112.  
  1113.         case autoKey:
  1114.         case keyDown:
  1115.             key = event->message & charCodeMask;
  1116.             switch (key)
  1117.             {
  1118.                 case 'q':
  1119.                 case 'Q':
  1120.                     if (event->modifiers & cmdKey)
  1121.                     gDone = true;
  1122.                     break;
  1123.             }
  1124.             break;
  1125.  
  1126.         case osEvt:
  1127.             switch ((event->message >> 24) & 0xFF) 
  1128.             {
  1129.                     /* Must logical and with 0xFF to get only low byte. */
  1130.                     /* High byte of message. */
  1131.  
  1132.                 case mouseMovedMessage:
  1133.                     break;
  1134.  
  1135.                 case suspendResumeMessage:
  1136.                         /* Suspend/resume is also an activate/deactivate. */
  1137.                     if ((event->message) & resumeFlag)
  1138.                         ClrInBackGndFlag(gFlags);    // process has come to the foreground
  1139.                     else
  1140.                         SetInBackGndFlag(gFlags);    // process has gone into background
  1141.                     break;
  1142.             }
  1143.             break;
  1144.  
  1145.         case diskEvt:
  1146.             if (HiWord(event->message) != noErr) 
  1147.             {
  1148.                 SetPt(&pt, kDILeft, kDITop);
  1149.                 DIBadMount(pt, event->message);
  1150.             }        /* It is not a bad idea to at least call DIBadMount in response to */
  1151.             break;    /* a diskEvt, so that the user can format a floppy. */
  1152.     }
  1153.  
  1154. }
  1155.  
  1156.  
  1157. /*******************************************************************************
  1158. ** DoBind
  1159. **    Implements the option to set the qlen field and to bing with an nbpName
  1160. **    by setting the nbpName field with a pointer to an entity name.
  1161. **     If nbpName is not nil, you must also set the nbpNameLen to the size of the
  1162. **    nbpName field. Note, nbpName is not a pascal nor a C string.  
  1163. ********************************************************************************/
  1164.  
  1165. OSStatus DoBind(EndpointRef ep, UInt8 socket, UInt8 type, OTQLen qlen, 
  1166.                     char *nbpName, UInt32 nbpNameLen)
  1167. {
  1168.     TBind            req, ret;
  1169.     OSStatus         err = kOTNoError;
  1170.     DDPNBPAddress    addr;
  1171.     
  1172.  
  1173.     // init the DDPAddress variable    
  1174.     if (nbpName == nil)        // are we registering with no nbp name
  1175.     {
  1176.         addr.fAddressType = AF_ATALK_DDP;        // set the address type
  1177.         req.addr.len    = kDDPAddressLength;
  1178.     }
  1179.     else
  1180.     {
  1181.         addr.fAddressType = AF_ATALK_DDPNBP;    // registering with an nbp name
  1182.                                                 // copy the name to the name buffer
  1183.         BlockMove(nbpName, &addr.fNBPNameBuffer, nbpNameLen);
  1184.                                                 // set the request length to include the name len
  1185.         req.addr.len    = kDDPAddressLength + nbpNameLen;
  1186.     }
  1187.     
  1188.     addr.fNetwork = 0;
  1189.     addr.fNodeID = 0;
  1190.     addr.fSocket = socket;
  1191.     addr.fDDPType = type;
  1192.     
  1193.     // set up the request
  1194.     req.addr.buf    = (UInt8*)&addr;
  1195.     req.qlen        = qlen;
  1196.     
  1197.     // set up the response
  1198.     ret.addr.buf    = (UInt8*)&addr;
  1199.     ret.addr.maxlen    = sizeof(addr);
  1200.  
  1201.     fprintf(stderr, "Doing Bind\n");
  1202.  
  1203.     //
  1204.     // Try to bind
  1205.     // 
  1206.     err = OTBind(ep, &req, &ret);
  1207.  
  1208.     if ( err != kOTNoError )
  1209.     {
  1210.         fprintf(stderr, "PAPSample: DoBind returns error %ld\n", err);
  1211.         return err;
  1212.     }
  1213.  
  1214.     fprintf(stderr, "Bound address = ");
  1215.     ShowDDPAddress((DDPAddress*)&addr);
  1216.     fprintf(stderr, "\n");
  1217.     fprintf(stderr, "Bound queue len is %ld\n", ret.qlen);
  1218.  
  1219.     fprintf(stderr, "After Bind, ");
  1220.     ShowEndpointState(ep, "");
  1221.  
  1222.     return err;
  1223. }
  1224.  
  1225.  
  1226.  
  1227. /*******************************************************************************
  1228. ** ActivatePAPEndpoint
  1229. ** 
  1230. ********************************************************************************/
  1231.  
  1232. OSStatus ActivatePAPEndpoint(MyEndpointRef *myEp)
  1233. {
  1234.     OSStatus    err = kOTNoError;
  1235.     
  1236.     //
  1237.     // Create a PAP endpoint
  1238.     // Open listener, using the tilisten module to make 
  1239.     // listen/accept/disconnect processing much simpler.
  1240.     //
  1241.     myEp->ep = OTOpenEndpoint(OTCreateConfiguration("tilisten, pap"), 0, NULL, &err);
  1242.  
  1243.     if ( myEp->ep == NULL || err != kOTNoError )
  1244.     {
  1245.         myEp->ep = NULL;
  1246.         
  1247.         if (err == kOTNoError)
  1248.             err = memFullErr;
  1249.             
  1250.         fprintf(stderr,"ERROR: OpenEndpoint(\"pap\") failed with %ld\n", err);
  1251.     }
  1252.     else
  1253.     {
  1254.         SetEPActiveFlag(myEp->flags);
  1255.     }
  1256.  
  1257.     /*-------------------------------------------------------------------------
  1258.     Enable self send
  1259.         have to do this before we set the endpoint into async mode.
  1260.     ------------------------------------------------------------------------- */
  1261.     if (err == kOTNoError)
  1262.     {
  1263.         err = DoNegotiateSelfSendOption(myEp->ep, 1);
  1264.         
  1265.         if (err <= kOTNoError)
  1266.         {
  1267.             fprintf(stderr, "error negotiating selfsend on main endpoint\n");
  1268.             err = kOTNoError;    // don't let this stop the app.
  1269.         }
  1270.         else
  1271.         {
  1272.             fprintf(stderr, "selfsend enabled\n");
  1273.             if (err == 0)
  1274.                 fprintf(stderr, "selfsend was previously off\n");
  1275.             else
  1276.                 fprintf(stderr, "selfsend was previously on\n");
  1277.         }
  1278.     }
  1279.  
  1280. #if HANDOFF_EP
  1281. #else
  1282.     // don't need EOM option
  1283.     if (err == kOTNoError)
  1284.     {
  1285.  
  1286.             // turn on the EOM option
  1287.         err = DoNegotiateEOMOption(myEp->ep, true);
  1288.         if (err != kOTNoError)
  1289.         {
  1290.             ClrEOMOnFlag(myEp->flags);
  1291.             fprintf(stderr, "\n\nError setting EOM option!\n");
  1292.         }
  1293.         else
  1294.         {
  1295.             SetEOMOnFlag(myEp->flags);
  1296.         }
  1297.     }
  1298. #endif
  1299.     
  1300.     if (err == kOTNoError)
  1301.     {
  1302.         //
  1303.         // Install notifier we're going to use for testing - we do this before
  1304.         //         binding - at this point, we're still synchronous
  1305.         //
  1306.         err = OTInstallNotifier(myEp->ep, EventHandler, (void*)myEp);
  1307.         if ( err != kOTNoError )
  1308.         {
  1309.             fprintf(stderr, "ERROR: InstallNotifier() failed with %ld\n for server endpoint", err);
  1310.         }
  1311.     }
  1312.         
  1313.     if (err == kOTNoError)
  1314.     {
  1315.  
  1316.         /*-------------------------------------------------------------------------
  1317.         Prepare to Bind the endpoint by getting the NBP Name
  1318.         ------------------------------------------------------------------------- */
  1319.  
  1320.         /*-------------------------------------------------------------------------
  1321.         Bind the endpoint endpoint.
  1322.         ------------------------------------------------------------------------- */
  1323.  
  1324.         err = DoBind(myEp->ep, kDynamicSocket, kATPType, 2, (char*)gServerNBPNameStr, clen((char*)gServerNBPNameStr));
  1325.         if ( err != kOTNoError )
  1326.         {
  1327.             fprintf(stderr, "PAPSample: bind of server endpoint failed.\n");
  1328.         }
  1329.         else
  1330.         {
  1331.             SetEPBoundFlag(myEp->flags);
  1332.             OTSetAsynchronous(myEp->ep);
  1333.         }
  1334.     }
  1335.  
  1336.     /*-------------------------------------------------------------------------
  1337.     Set the server status string
  1338.     ------------------------------------------------------------------------- */
  1339.     if (err == kOTNoError)
  1340.         BeginSetServerStatusOption(myEp->ep, kSetIdleStr);
  1341.     
  1342.     
  1343.     
  1344.     return err;
  1345. }
  1346.  
  1347. /*******************************************************************************
  1348. ** InitMyEndpointRef function - zero out the MyEndpointRef structure
  1349. **     Course we could use the memset function here.
  1350. ********************************************************************************/
  1351.  
  1352. OSStatus InitMyEndpointRef(MyEndpointRef *myEp)
  1353. {
  1354.     myEp->ep = nil;
  1355.     myEp->flags = 0;
  1356.     myEp->usedQ = OTAllocMem(sizeof(OTLIFO));
  1357.     if (myEp->usedQ == nil)
  1358.         return memFullErr;
  1359.     
  1360.     myEp->usedQ->fHead = nil;        // no packets with this endpoint.
  1361.     
  1362.     return kOTNoError;
  1363. }
  1364.  
  1365.  
  1366. OSStatus InitPAPBuffers(void)
  1367. {
  1368.     PacketPtr        packetPtr;
  1369.     OSStatus        err = kOTNoError;
  1370.     short            i;
  1371.     
  1372.         // allocate memory for the freeQ
  1373.     gFreeQ = OTAllocMem(sizeof(OTLIFO));
  1374.     if (gFreeQ == nil)
  1375.         return memFullErr;
  1376.         
  1377.     /* set up the free queue */
  1378.     gFreeQ->fHead = nil;
  1379.     
  1380.         // allocate a temp buffer to be used when packet data overlaps.
  1381.     gTempPackPtr = OTAllocMem(sizeof(PacketBuffer) + kPAPDataSize);    
  1382.     if (gTempPackPtr == nil)
  1383.         err = memFullErr;
  1384.  
  1385.     /* enqueue the packet buffer records to the free queue */
  1386.     for (i=0; (i<kNumBuffers) && (err == kOTNoError); i++)
  1387.     {
  1388.             // before calling OTAllocMem, we must have already have called
  1389.             // InitOpenTransport
  1390.             
  1391.         packetPtr = OTAllocMem(sizeof(PacketBuffer));
  1392.         if (packetPtr != nil)
  1393.         {
  1394.             packetPtr->flags = 0;
  1395.             packetPtr->fLink.fNext = nil;
  1396.             OTLIFOEnqueue(gFreeQ, &(packetPtr->fLink));    // first field is fLink field
  1397.             
  1398.         }
  1399.         else
  1400.             err = memFullErr;
  1401.     }
  1402.     
  1403.     if (err == kOTNoError)
  1404.     {
  1405.         /* show that the buffers have been init'd */
  1406.         SetBufsInitdFlag(gFlags);
  1407.  
  1408.         /* note that we don't need to worry about holding memory in the
  1409.             presence of VM.  The notifier routine will be called at
  1410.             deferred task time when it is safe to page memory
  1411.          */
  1412.         
  1413.     }
  1414.     else
  1415.     {
  1416.         fprintf(stderr, "\n\nError allocating receive buffers!\n");
  1417.         fprintf(stderr, "\nBye Bye.\n");
  1418.     }
  1419.         
  1420.     return(err);
  1421.  
  1422. }
  1423.  
  1424.     
  1425.  
  1426. /*******************************************************************************
  1427. ** Initialize OpenTransport and call DoTest function
  1428. ********************************************************************************/
  1429. OSStatus InitPAPServerStuff(void)
  1430. {
  1431.     OSStatus    err = kOTNoError;
  1432.     UInt32        growAmt, selection;
  1433.     UInt32        i;
  1434.     char        mystr[255];    
  1435.                 
  1436.         // register ourselves with OT
  1437.     OTRegisterAsClient((OTClientName) "PAPServerSample", nil);
  1438.  
  1439.         // ask whether to alter current options
  1440.     fprintf(stdout, "\nDo you want to change the current options?");
  1441.     fprintf(stdout, "\n  Options to change 1. SetMemoryLimits");
  1442.     fprintf(stdout, "\n                    2. Dump packets");
  1443.     selection = GetYesNoOption();
  1444.     if (selection == kQuitTest)
  1445.         err = -1;
  1446.     else if (selection == kAcceptOption)
  1447.     {
  1448.             // ask whether to use the set memory limits option or not
  1449.         fprintf(stdout, "\nDo you want to set memory limits?");
  1450.         selection = GetYesNoOption();
  1451.         
  1452.         if (selection == kQuitTest)
  1453.             err = -1;
  1454.         else if (selection == kAcceptOption)
  1455.         {
  1456.             fprintf(stderr, "How much memory to grow heap ?\n");
  1457.             if (gets(mystr) != 0)
  1458.             {
  1459.                 stringtonum(mystr, (long*)&growAmt);
  1460.                 OTSetMemoryLimits(growAmt, 0);
  1461.                 
  1462.             }
  1463.         }
  1464.         
  1465.         if (err == kOTNoError)
  1466.         {
  1467.                 // ask whether to use the set memory limits option or not
  1468.             fprintf(stdout, "\nDo you want to just dump packets?");
  1469.             selection = GetYesNoOption();
  1470.             if (selection == kQuitTest)
  1471.                 err = -1;
  1472.             else if (selection == kAcceptOption)
  1473.             {
  1474.                 SetdumpPktsFlag(gFlags);
  1475.             }
  1476.         }
  1477.     }
  1478.  
  1479.     if (err == kOTNoError)
  1480.     {
  1481.  
  1482.             // load in the various strings
  1483.         GetIndString((unsigned char*)&gIdleStr, kServerStrID, kIdleStrID);
  1484.         GetIndString((unsigned char*)&gBusyStr, kServerStrID, kBusyStrID);
  1485.         GetIndString((unsigned char*)&gServerNBPNameStr, kServerStrID, kServerNBPStrID);
  1486.             // covert each string to c
  1487.         p2c(gIdleStr);
  1488.         p2c(gBusyStr);
  1489.         p2c(gServerNBPNameStr);
  1490.     
  1491.         // initialize the endpoint ref
  1492.         err = InitMyEndpointRef(&gEp);
  1493.     }
  1494.     
  1495.     if (err == kOTNoError)
  1496.     {
  1497. #if HANDOFF_EP
  1498.         for (i = 0; (i < kMaxHandoffEPs) && (err == kOTNoError) ; i++)
  1499.             err = InitMyEndpointRef(&gHandoffEp[i]);
  1500. #endif
  1501.     }
  1502.  
  1503.     if (err == kOTNoError)
  1504.     {
  1505.         //
  1506.         // Initialize the buffers
  1507.         //
  1508.         err = InitPAPBuffers();
  1509.     }
  1510.             
  1511.  
  1512.     if (err == kOTNoError)
  1513.     {
  1514.         //
  1515.         //  Init the server endpoint
  1516.         //
  1517.         err = ActivatePAPEndpoint(&gEp);
  1518.     }
  1519.  
  1520. #if HANDOFF_EP
  1521.     if (err == kOTNoError)
  1522.     {
  1523.         //
  1524.         //  Init the handoff endpoint
  1525.         //
  1526.         for (i = 0; (i < kMaxHandoffEPs) && (err == kOTNoError); i++)
  1527.             gHandoffEp[i].ep = OTOpenEndpoint(OTCreateConfiguration(kPAPName), (OTOpenFlags)NULL, NULL, &err);
  1528.  
  1529.         if (err != kOTNoError)
  1530.         {
  1531.             fprintf(stderr, "\n\nError opening the handoff endpoint!\n");
  1532.             fprintf(stderr, "\nBye Bye.\n");
  1533.         }
  1534.         else
  1535.         {
  1536.             for (i = 0; (i < kMaxHandoffEPs) && (err == kOTNoError); i++)
  1537.             { 
  1538.                 SetEPActiveFlag(gHandoffEp[i].flags);
  1539.                     // turn on the EOM option
  1540.                 err = DoNegotiateEOMOption(gHandoffEp[i].ep, true);
  1541.                 if (err != kOTNoError)
  1542.                 {
  1543.                     ClrEOMOnFlag(gHandoffEp[i].flags);
  1544.                     fprintf(stderr, "\n\nError setting EOM option!\n");
  1545.                 }
  1546.                 else
  1547.                 {
  1548.                     SetEOMOnFlag(gHandoffEp[i].flags);
  1549.                 }
  1550.             }
  1551.         }
  1552.     }
  1553.  
  1554.  
  1555.     if (err == kOTNoError)
  1556.     {
  1557.         for (i = 0; (i < kMaxHandoffEPs) && (err == kOTNoError); i++)
  1558.         {
  1559.             err = OTInstallNotifier(gHandoffEp[i].ep, EventHandler, (void*)&gHandoffEp[i]);
  1560.             if ( err != kOTNoError )
  1561.             {
  1562.                 fprintf(stderr, "ERROR: InstallNotifier() failed with %ld\n for handoff endpoint", err);
  1563.             }
  1564.             else
  1565.                 OTSetAsynchronous(gHandoffEp[i].ep);
  1566.         }
  1567.  
  1568.     }
  1569. #endif        // HANDOFF_EP    
  1570.         
  1571.     return err;
  1572.     
  1573. }
  1574.  
  1575.  
  1576. /*******************************************************************************
  1577. ** ReleasePAPMemory
  1578. ********************************************************************************/
  1579.  
  1580. void ReleasePAPMemory(void)
  1581. {
  1582.     PacketPtr    packetPtr;
  1583.     OTLIFO        *otLIFOPtr;
  1584.     short        i, j;
  1585.     OSErr        err;
  1586.     
  1587.     if (gTempPackPtr)
  1588.         OTFreeMem(gTempPackPtr);
  1589.         
  1590.         // first release the freeQ memory
  1591.     otLIFOPtr = gFreeQ;
  1592.     packetPtr = (PacketPtr)OTLIFODequeue(otLIFOPtr);
  1593.     
  1594.     while (packetPtr != nil)    // while the queue is not empty
  1595.     {
  1596.                 // free the packetbuffer
  1597.         OTFreeMem(packetPtr);
  1598.         packetPtr = (PacketPtr)OTLIFODequeue(otLIFOPtr);            
  1599.     }
  1600.  
  1601. #if HANDOFF_EP
  1602.     for (i = 0; i < kMaxHandoffEPs; i++)        // 
  1603.     {
  1604.         otLIFOPtr = gHandoffEp[i].usedQ;
  1605. #else
  1606.         otLIFOPtr = gEp.usedQ;
  1607. #endif
  1608.         if (otLIFOPtr->fHead)
  1609.             fprintf(stderr, "Am releasing buffer from the used queue.\n\n");
  1610.         
  1611.         packetPtr = (PacketPtr)OTLIFODequeue(otLIFOPtr);
  1612.         
  1613.         while (packetPtr != nil)    // while the queue is not empty
  1614.         {
  1615.                     // free the packetbuffer
  1616.             OTFreeMem(packetPtr);
  1617.             packetPtr = (PacketPtr)OTLIFODequeue(otLIFOPtr);            
  1618.         }
  1619.     
  1620. #if HANDOFF_EP
  1621.     }
  1622. #endif
  1623.     
  1624.     OTFreeMem(gFreeQ);
  1625.     
  1626. }
  1627.  
  1628. /*******************************************************************************
  1629. ** Close endpoints, and OpenTransport 
  1630. ********************************************************************************/
  1631.  
  1632. void ClosePAPServerStuff(void)
  1633. {
  1634.  
  1635.     short i;
  1636.  
  1637.     if (gEp.ep)
  1638.         OTSetSynchronous(gEp.ep);
  1639.  
  1640.     // note that we don't check whether the endpoint is still connected.  Since
  1641.     // we are leving anyway, let the UnBind call clear things up.  If we did do a
  1642.     // disconnect here, we would meed to also implement a timer mechanism. so that
  1643.     // we didn't get hung awaiting a DisconnectComplete event that might not come.
  1644.     
  1645. #if HANDOFF_EP
  1646.     for (i = 0; i < kMaxHandoffEPs; i++)
  1647.     {
  1648.  
  1649.         if (gHandoffEp[i].ep)
  1650.             OTSetSynchronous(gHandoffEp[i].ep);
  1651.         
  1652.         if (TstEPBoundFlag(gHandoffEp[i].flags))    // is the handoff endpoint bound
  1653.             OTUnbind(gHandoffEp[i].ep);            // unbind the endpoint
  1654.         
  1655.         if (gHandoffEp[i].usedQ != nil)            // free allocated memory with usedQ.
  1656.             OTFreeMem(gHandoffEp[i].usedQ);
  1657.             
  1658.         if (TstEPActiveFlag(gHandoffEp[i].flags))    // is the handoff endpoint open
  1659.             OTCloseProvider(gHandoffEp[i].ep);        // close the endpoint
  1660.             
  1661.     }
  1662.  
  1663. #endif
  1664.             
  1665.     if (TstEPBoundFlag(gEp.flags))            // is the server endpoint bound
  1666.         OTUnbind(gEp.ep);                    // unbind the endpoint
  1667.         
  1668.     if (gEp.usedQ != nil)                    // free allocated memory with usedQ.
  1669.         OTFreeMem(gEp.usedQ);
  1670.         
  1671.     if (TstEPActiveFlag(gEp.flags))            // is the server endpoint open
  1672.         OTCloseProvider(gEp.ep);            // close the endpoint
  1673.         
  1674.     // ReleasePAPMemory();                        // release memory before OT goes away
  1675.                                             // not really necessary since we are just going to 
  1676.                                             // exit after this.
  1677.  
  1678.     if (gFreeQ != nil)
  1679.         OTFreeMem(gFreeQ);
  1680.     
  1681.     if (TstOTActiveFlag(gFlags))            // is OpenTransport active
  1682.         CloseOpenTransport();                // shutdown OT services
  1683.     
  1684. }
  1685.  
  1686. //
  1687. //    NetInit:
  1688. //
  1689. //    This routine does various networking related startup tasks:
  1690. //
  1691. //    (1) it does InitOpenTransport
  1692. //    (2) it records the OT version for us.
  1693. //
  1694. //  result - true - OpenTransport init'd and the correct version is present
  1695. //             false - problem opening OT or OT version not correct
  1696. //
  1697. static Boolean NetInit()
  1698. {
  1699.     OSStatus err;
  1700.  
  1701.     err = Gestalt(gOTVersionSelector, (long*) &gOTVersion);
  1702.     if (err || (gOTVersion < kOTVersion111))
  1703.     {
  1704.         fprintf(stderr, "Please install Open Transport 1.1.1 or later");
  1705.         return false;
  1706.     }
  1707.     
  1708.     err = InitOpenTransport();
  1709.     if (err)
  1710.     {
  1711.         fprintf(stderr, "NetInit: InitOpenTransport error %d", err);
  1712.         return false;
  1713.     }
  1714.     return true;
  1715. }
  1716.  
  1717.  
  1718. /*******************************************************************************
  1719. ** main function
  1720. ********************************************************************************/
  1721.  
  1722. main(void) 
  1723. {
  1724.     OSStatus    osstatus;
  1725.     
  1726.     InitGraf(&qd.thePort);                    // initialize quickdraw so we can use regions
  1727.  
  1728.     fprintf(stderr, "PAPServerSample showing implementation of PAP server.\n\n");
  1729.  
  1730.     // init the flags variable
  1731.     gFlags = 0;
  1732.  
  1733. #if DO_DEBUG_LOG
  1734.     DebugStr("\p doing log;dx;log papserver;g");
  1735. #endif
  1736.  
  1737.     if (NetInit() == false)
  1738.         return 0;
  1739.     
  1740.     //
  1741.     // Initialize the OT and the global Endpoints
  1742.     //
  1743.     osstatus = InitPAPServerStuff();
  1744.     
  1745.     if (osstatus == kOTNoError)
  1746.     {
  1747.     
  1748.  
  1749.         //
  1750.         // Run the PAPServer code
  1751.         //
  1752.         DoServer();
  1753.         //
  1754.     }
  1755.     
  1756.     //
  1757.     // Close things down
  1758.     //
  1759.     ClosePAPServerStuff();
  1760.     
  1761.     CheckFileToClose();
  1762.     
  1763.     fprintf(stderr, "\n\nDone\n");
  1764.         
  1765.     return 0;
  1766. }
  1767.  
  1768. void DoValueBreak(long value, const char* message)
  1769. {
  1770.     static short    sDoErrorBreak = 0;
  1771.  
  1772.     {
  1773.         Str255    s,
  1774.                 n = "\p";
  1775.  
  1776.         s[0] = strlen(message);
  1777.         BlockMoveData(message,&s[1],s[0]);
  1778.         if (value < 0)
  1779.         {
  1780.             s[0] += 1;
  1781.             s[s[0]] = '-';
  1782.             value = -value;
  1783.         }
  1784.         while (value)
  1785.         {
  1786.             if (n[0])
  1787.                 BlockMoveData(&n[1],&n[2],n[0]);
  1788.             n[0]++;
  1789.             n[1] = 48 + (value % 10);
  1790.             value /= 10;
  1791.         }
  1792.         BlockMoveData(&n[1],&s[s[0]+1],n[0]);
  1793.         s[0] += n[0];
  1794.  
  1795.         sDoErrorBreak++;
  1796.         {
  1797.             short    cnt = sDoErrorBreak;
  1798.  
  1799.             s[0]++;
  1800.             s[s[0]] = ',';
  1801.             s[0]++;
  1802.             s[s[0]] = ' ';
  1803.             n[0] = 0;
  1804.             while (cnt)
  1805.             {
  1806.                 if (n[0])
  1807.                     BlockMoveData(&n[1],&n[2],n[0]);
  1808.                 n[0]++;
  1809.                 n[1] = 48 + (cnt % 10);
  1810.                 cnt /= 10;
  1811.             }
  1812.             BlockMoveData(&n[1],&s[s[0]+1],n[0]);
  1813.             s[0] += n[0];
  1814.         }
  1815.         DebugStr(s);
  1816.     }
  1817. }
  1818.  
  1819.  
  1820. OSStatus BeginSetServerStatusOption(EndpointRef ep, UInt16 whichStr)
  1821. {
  1822.     OSStatus    err;
  1823.     unsigned char    *in = "\p._in";
  1824.     
  1825.     if (whichStr == kSetIdleStr)
  1826.     {
  1827.         err = DoSetServerStatusOption(ep, (char*)&gIdleStr);
  1828.     }
  1829.     else
  1830.     {
  1831.         err = DoSetServerStatusOption(ep, (char*)&gBusyStr);
  1832.     }
  1833.     
  1834.     if (err != kOTNoError)
  1835.     {
  1836.         fprintf(stderr, "ServerStatus option call failed\n");
  1837.         fprintf(stderr, "however, this will not keep the server from running\n");
  1838.         err = kOTNoError;
  1839.     }
  1840.     
  1841.     return err;
  1842. }
  1843.  
  1844.  
  1845. UInt32 GetYesNoOption(void)
  1846. {
  1847.     UInt32    result;
  1848.     char    selection[32];
  1849.     Boolean    done;
  1850.     
  1851.     fprintf(stdout, "\n    Enter Y - To accept option");
  1852.     fprintf(stdout, "\n    Enter N - To decline option");
  1853.     fprintf(stdout, "\n    Enter Q - To quit");
  1854.     fprintf(stdout, "\nYour selection -> ");
  1855.     fflush(stdout);
  1856.     done = false;
  1857.  
  1858.     do
  1859.     {
  1860.         if (gets(selection) != 0)
  1861.         {
  1862.             switch (selection[0])
  1863.             {
  1864.                 case 'y':
  1865.                 case 'Y':
  1866.                     result = kAcceptOption;
  1867.                     done = true;
  1868.                     break;
  1869.                 
  1870.                 case 'n':
  1871.                 case 'N':
  1872.                     result = kDeclineOption;
  1873.                     done = true;
  1874.                     break;
  1875.  
  1876.                 case 'q':
  1877.                 case 'Q':
  1878.                     result = kQuitTest;
  1879.                     done = true;
  1880.                     break;
  1881.                     
  1882.                 default:
  1883.                     fprintf(stdout, "\nInvalid entry - %c, try again -> ", selection);
  1884.                     fflush(stdout);
  1885.                     break;
  1886.  
  1887.             }
  1888.         }
  1889.     } while (!done);
  1890.     
  1891.     fflush (stdout);
  1892.     return result;
  1893. }
  1894.  
  1895.  
  1896. #if HANDOFF_EP
  1897. /*
  1898.     Iterate through the handoff endpoints and find one that doesn't have the busy flag
  1899.     set - return the pointer else return null
  1900. */
  1901. MyEndpointRef*    FindFreeHandoffEp(void)
  1902. {
  1903.     short    i;
  1904.     
  1905.     for (i = 0; i < kMaxHandoffEPs; i++)
  1906.     {
  1907.         if (TstEPBusyFlag(gHandoffEp[i].flags) == false)
  1908.             return &gHandoffEp[i];
  1909.     }
  1910.     
  1911.     return nil;
  1912. }
  1913. #endif
  1914.  
  1915. Boolean EndpointsAllBusy(void)
  1916. {
  1917.     Boolean        result = true;    
  1918. #if HANDOFF_EP
  1919.     short        i;
  1920.     
  1921.     for (i = 0; (i < kMaxHandoffEPs) && (result == true); i++)
  1922.     {
  1923.         if (TstEPBusyFlag(gHandoffEp[i].flags) == false)
  1924.             result = false;    // any endpoint not busy means that not all eps are busy
  1925.     }
  1926.  
  1927. #else
  1928.     result = TstEPBusyFlag(gEp.flags);
  1929.         
  1930. #endif
  1931.     
  1932.     return result;
  1933. }